// fare testo refresh sull'open
//fare testo selezionabile che non si dragga da aperto
// devo salvare la linea da cui starta a prendere il codice la nuova bolla o non posso moddarlo dopo

var arrayBubble = [];
var draggedBubble = null;

var tmpMouseXPosition;
var tmpMouseYPosition;

var originalMiniX;
var originalMiniY;

var redoTimer = null;
var innerFolder;
var innerFunctionCounter = 0
var workingBubble = null;
var lastIndex = 0;

var myPathName = []
var pathIndex = []

// bubble object
function Bubble(parent, signature, body, file) {
	var file = file;
	var groupID = 0;
	var parent = parent;
	var signature = signature;
	var bodyValue = body;
	var editable = false;
	var bubbleID;
	var bubble = null;
	var beingDragged = false;
	var isOpen = false;
	var container = null;
	var title = null;
	var top;
	var left;
	var openChildArray = [];
	var bubblePosition = [];
	var originalGroupElements = [];
	var originalGroupMiniElements = [];
	var parentBubble = 0;
	var editableArea;
	var minibubble = null;
	var changingLine = {};

	function returnParent() {
		return parent;
	}

	function returnBody() {
		return bodyValue
	}

	function returnSignature() {
		return signature
	}

	function returnEditable() {
		return editable;
	}

	function setEditable(bool) {
		editable = bool;
	}

	function returnBubbleID() {
		return bubbleID
	}

	function computeBubbleHeightAfterDblClick() {

		var newHeight = 0;

		if(editableArea.lineCount() < 15) {
			for( i = 0; i < editableArea.lineCount(); i++) {
				newHeight += 25;
			}
			return newHeight;
			//+ "px";
		} else {
			return 300;
			//bubble.style.height = "300px";
		}

	}

	function createListArgs(key) {
		var string = "";
		for(i in functionArray[key][1]) {
			string += functionArray[key][1][i] + "[,]*[\\s]*";

		}
		return string;
	}

	function foldInnerFunction() {
		var tmp = 0;
		innerFolder = CodeMirror.newFoldFunction(CodeMirror.braceRangeFinder);

		for( k = bubbleID + 1; k < functionArray.length; k++) {
			if(functionArray[k][0] == null) {
				var myregex = new RegExp('[\\s]*function[\\s]*[(][\\s]*' + createListArgs(k) + '[)][\\s]*')
			} else
				var myregex = new RegExp('[\\s]*function[\\s]*' + functionArray[k][0] + '[\\s]*[(][\\s]*' + createListArgs(k) + '[)][\\s]*')
			for( i = tmp; i < editableArea.lineCount(); i++) {
				tmp = i;
				if(editableArea.getLine(i).match(myregex)) {
					innerFunctionCounter = k;
					innerFolder(editableArea, i)
					if(functionArray[k][0] == null)
						editableArea.setMarker(i, "<span style=\"color: #900\" id='lineMarkerId" + i + "'onclick='clickForInner(" + k + ")'>●</span> %N%");
					else {

						editableArea.setMarker(i, "<span style=\"color: #900\" id='lineMarkerId" + i + "'onclick='clickForDefined(" + k + ")'>{..}</span> %N%");

					}
					tmp++;
					break;
				}

			}

		}

	}

	function checkFolding(editor, line) {
		var info = editor.lineInfo(line);
		if(info.markerText == '<span style="color:#600">&#x25bc;</span>%N%' || info.markerText == null)
			innerFolder(editableArea, line)
	}

	function checkNewBubble(changes) {
		//console.log(changes.text[0]) .from.line
		if(changingLine[changes.from.line])
			//if(changes.text[0] == "")
			//	changingLine[changes.from.line] = changingLine[changes.from.line].slice(0, changes.from.ch) + changingLine[changes.from.line].slice(changes.from.ch + 1)
			//else
			changingLine[changes.from.line] = changingLine[changes.from.line].slice(0, changes.from.ch) + changes.text[0] + changingLine[changes.from.line].slice(changes.from.ch)
		else
			changingLine[changes.from.line] = changes.text[0]
		console.log(changes.from.line + "   " + changingLine[changes.from.line])

		if(changes.text[0] == '}') {
			try {
				//ast = parse(changingLine[changes.from.line]);
				w = new ast_walker();
				//var x = w.walk(ast);

				w.with_walkers({
					"defun" : pushDefun,
					"function" : pushFun
				}, function() {
					w.walk(parse(changingLine[changes.from.line]));
					return add_bubble(file)//addNewFunction(arrayBubble.length, file)
				});
				//console.log(arrayBubble.length)
			} catch(e) {
			}
			//editableArea.focus()
			foldInnerFunction();
		}

	}

	function avoidChange(what) {
		if(editableArea.lineInfo(what.from.line).markerText == "<span style=\"color: #900\" id='" + what.from.line + "'onclick='clickForInner(parseInt(this.id))'>●</span> %N%" || editableArea.lineInfo(what.from.line).markerText == "<span style=\"color: #900\" id='" + what.from.line + "'onclick='clickForDefined(parseInt(this.id))'>{..}</span> %N%") {
			return false;
		}

	}

	function callCodeMirror(id) {
		editableArea = CodeMirror.fromTextArea(document.getElementById(id), {
			mode : "javascript",
			tabMode : "indent",
			gutter : true,
			//lineNumbers : true,
			lineWrapping : true,
			matchBrackets : true,
			onHighlightComplete : function() {
				editableArea.refresh()
			},
			onUpdate : function() {
				editableArea.refresh()
			},
			onGutterClick : checkFolding,
			theme : "eclipse",
			onChange : function(editor, what) {//avoidChange(what);
				sendCodeCoop(workingBubble);
				//checkNewBubble(what)
			}
		});

		//console.log(document.getElementsByClassName(bubble + " CodeMirror-scroll"));
		foldInnerFunction();

		if(signature == "inner Function") {
			editableArea.getGutterElement().style.backgroundColor = '#ffa200'
		} else {
			editableArea.getGutterElement().style.backgroundColor = '#65be6a'
		}
	}

	function openBubble(id) {
		if(!document.getElementById("editableBubble" + id)) {
			area = document.createElement("textarea")
			area.setAttribute("id", "editableBubble" + id)
			minibubble = document.getElementById("minibubbleNumber" + id)

			bubble.removeChild(title)
			bubble.appendChild(area);
			document.getElementById("editableBubble" + id).value = bodyValue;
			callCodeMirror("editableBubble" + id);
			if(signature != "inner Function") {
				bubble.setAttribute("class", "ui-widget-content ui-draggable ")
			} else {
				bubble.setAttribute("class", "openInner ui-draggable")
			}
			//
			// $(bubble).mousedown(function() {
			// $(container).draggable({
			// disabled : true
			// })
			// })
			//
			// $(bubble).mouseup(function() {
			// $(container).draggable({
			// disabled : false
			// })
			// })
		}

		$(container).animate({
			opacity : "0"
		}, 50, function() {

			//area.setAttribute("style", "-webkit-transition:width 2s")

			isOpen = true;

			$(bubble).animate({
				height : computeBubbleHeightAfterDblClick(),
				width : "400"
			}, 100, function() {
				editableArea.refresh()
				$(bubble.lastChild).animate({
					opacity : "1"
				}, 500, function() {
					editableArea.refresh()
				})

				$(minibubble).css("width", 400 / 15)
				$(minibubble).css("height", computeBubbleHeightAfterDblClick() / 15)

				$(container).css("width", "404")
				$(container).css("height", computeBubbleHeightAfterDblClick() + 4)
				$(container).animate({
					opacity : "1"
				}, 100, function() {

				});
			})

			$(container).resizable({
				disabled : false,
				alsoResize : $(bubble),
				start : function() {setUpOnBody()
				},
				resize : function() {
					editableArea.refresh()
					$(minibubble).css("width", parseInt($(container).css("width").split("px")[0]) / 15)
					$(minibubble).css("height", parseInt($(container).css("height").split("px")[0]) / 15)
				}
			})

		});
	}

	function closeBubble(id) {
		minibubble = document.getElementById("minibubbleNumber" + id)
		$(container).animate({
			opacity : "0"
		}, 50, function() {
			if(document.getElementById("editableBubble" + id)) {
				bubble.setAttribute("class", "closedbubble ui-draggable")
				bodyValue = editableArea.getValue()
				bubble.removeChild(bubble.lastChild);
				bubble.removeChild(document.getElementById("editableBubble" + id))
				bubble.appendChild(title);
				$(container).css("width", "104")
				$(container).css("height", "38")
				$(minibubble).css("width", 100 / 15)
				$(minibubble).css("height", 38 / 15)
				$(bubble).animate({
					height : "33",
					width : "100"
				}, 100, function() {
					$(container).animate({
						opacity : "1"
					}, 100)
				});
				isOpen = false;

			}
		});

		$(container).resizable({
			disabled : true
		})
	}

	function moveBubbleGroup(groupid, ui) {
		var diffY = ui.originalPosition.top - ui.position.top;
		var diffX = ui.originalPosition.left - ui.position.left;
		for( i = 0; i < originalGroupElements.length; i++) {
			//console.log("boh")
			// here the evil stuff to move all the other bubbles

			if(parseInt(originalGroupElements[i][1].split("px")[0]) - diffY >= 63) {

				document.getElementById("container" + originalGroupElements[i][0]).style.top = parseInt(originalGroupElements[i][1].split("px")[0]) - diffY
				document.getElementById("container" + originalGroupElements[i][0]).style.left = parseInt(originalGroupElements[i][2].split("px")[0]) - diffX
				document.getElementById("minibubbleNumber" + originalGroupMiniElements[i][0]).style.top = parseInt(originalGroupMiniElements[i][1].split("px")) - diffY / 15
				document.getElementById("minibubbleNumber" + originalGroupMiniElements[i][0]).style.left = parseInt(originalGroupMiniElements[i][2].split("px")) - diffX / 15
			} else {
				document.getElementById("container" + originalGroupElements[i][0]).style.top = "63px"
				document.getElementById("minibubbleNumber" + originalGroupMiniElements[i][0]).style.top = "11px"
				return false

			}
		}

	}

	function removeBubbleForEver() {

		//arrayBubble.splice(arrayBubble.indexOf(bubble))
		if(parentBubble != null)
			//arrayBubble[parentBubble].bubble.getArrayChildren()[(arrayBubble[parentBubble].bubble.getArrayChildren().indexOf(arrayBubble[workingBubble].bubble))] == null;
			(arrayBubble[parentBubble].bubble.getArrayChildren()).splice((arrayBubble[parentBubble].bubble.getArrayChildren().indexOf(arrayBubble[workingBubble].bubble)), 1);

		document.getElementById("body").removeChild(document.getElementById("container" + bubbleID))
		document.getElementById("navigator").removeChild(document.getElementById("minibubbleNumber" + bubbleID))
		draggedBubble = null;

	}

	function unselectBubble() {
		for( i = 0; i < bubbleID; i++) {
			document.getElementById("functionNumber" + i).setAttribute("style", "-webkit-box-shadow:none")
		}
	}

	function createBubble(key) {
		parentBubble = workingBubble;
		minibubbleID = key
		bubbleID = key;
		groupID = bubbleID
		containerID = key

		///elements creation
		container = document.createElement("div")
		bubble = document.createElement("div");
		minibubble = document.createElement("div")
		title = document.createElement("div");

		/// here i append stuff togheter
		bubble.appendChild(title);
		document.getElementById('body').appendChild(container)
		container.appendChild(bubble);
		document.getElementById("navigator").appendChild(minibubble);

		/// container setting
		container.setAttribute("id", "container" + key)
		container.setAttribute("class", "bubbleborder ui-draggable")
		$(container).css("position", "absolute")
		$(container).css("zIndex", "0")
		if(workingBubble == null)
			$(container).css("top", 100)
		else
			$(container).css("top", parseInt(document.getElementById("container" + workingBubble).style.top.split("px")) + 60 * arrayBubble[workingBubble].bubble.getArrayChildren().length)
		if(workingBubble == null)
			$(container).css("left", 42)
		else {
			$(container).css("left", parseInt(document.getElementById("container" + workingBubble).style.left.split("px")) + parseInt(document.getElementById("container" + workingBubble).style.width.split("px")) + 20)
		}
		bubble.style.overflow = "hidden"
		bubble.setAttribute("id", "functionNumber" + key);
		bubble.setAttribute("class", "closedbubble ui-draggable ");
		$(bubble).css("position", "relative")
		$(bubble).css("zIndex", "1")
		$(bubble).css("top", 0)
		$(bubble).css("left", 0)

		///minibubble  setting
		minibubble.setAttribute("id", "minibubbleNumber" + key)
		minibubble.setAttribute("style", "position:absolute")

		minibubble.setAttribute("class", "ui-widget-content-mini");
		if(signature == "inner Function") {
			minibubble.style.backgroundColor = '#fff5c0'
		} else {
			minibubble.style.backgroundColor = '#d9ffdb'
		}
		if(signature == "inner Function") {
			minibubble.style.borderColor = '#ffa200'
		} else {
			minibubble.style.borderColor = '#65be6a'
		}
		$(minibubble).css("top", (parseFloat(document.getElementById("container" + key).style.top.split("px")[0]) / 15 + parseFloat(document.getElementById("Navigator_index").style.top.split("px")[0]) ))
		$(minibubble).css("left", (parseFloat(document.getElementById("container" + key).style.left.split("px")[0]) / 15 + parseFloat(document.getElementById("Navigator_index").style.left.split("px")[0]) + 2))

		///title setting
		title.setAttribute("class", "b_title");
		title.innerHTML = this.signature();

		///bubble event setting
		$(container).draggable({
			disabled : false,
			scrollSpeed : 40,
			containment : 'window',
			snap : true,
			snapTolerance : 5,
			snapMode : "outer",
			appendTo : 'body',
			start : function(event, ui) {
				originalGroupElements = []
				originalGroupMiniElements = []
				originalMiniX = (parseInt(document.getElementById("minibubbleNumber" + key).style.left.split("px")[0]));
				originalMiniY = (parseInt(document.getElementById("minibubbleNumber" + key).style.top.split("px")[0]));

				for( i = 0; i < arrayBubble.length; i++) {
					if(arrayBubble[i].bubble.getGroupNumber() == groupID && document.getElementById("container" + arrayBubble[i].bubble.bubbleID())) {
						originalGroupElements.push([i, document.getElementById("container" + arrayBubble[i].bubble.bubbleID()).style.top, document.getElementById("container" + arrayBubble[i].bubble.bubbleID()).style.left])
						originalGroupMiniElements.push([i, document.getElementById("minibubbleNumber" + arrayBubble[i].bubble.bubbleID()).style.top, document.getElementById("minibubbleNumber" + arrayBubble[i].bubble.bubbleID()).style.left])

					}
				}
			},
			drag : function(event, ui) {

				if(alt) {
					return moveBubbleGroup(groupID, ui);
				}

				if((parseInt($(container).css("top").split("px")[0])) >= 63) {
					document.getElementById("minibubbleNumber" + key).style.top = originalMiniY - ((ui.originalPosition.top - ui.position.top) / 15) + "px";
					document.getElementById("minibubbleNumber" + key).style.left = originalMiniX - ((ui.originalPosition.left - ui.position.left) / 15) + "px";
					return true
				} else {
					document.getElementById("container" + key).style.top = "63px"
					document.getElementById("minibubbleNumber" + key).style.top = "11px"
					return false

				}
			},
			stop : function(event, ui) {
				//alt = false;
				originalGroupElements = [];
				var snapped = $(this).data('draggable').snapElements;

				var snappedTo = $.map(snapped, function(element) {
					return element.snapping ? element.item : null;
				});
				//$(this).bubbleID = snappedTo[0].getAttribute("id").split("container")[1]
				if(snappedTo.length > 0) {
					groupID = arrayBubble[parseInt((snappedTo[0].getAttribute("id").split("container")[1]))].bubble.getGroupNumber();

					$(this).css("backgroundColor", $(snappedTo[0]).css("backgroundColor"))
				} else {

					//document.getElementById('minibubbleNumber' + key).style.backgroundColor = 'rgba(221,142,238, 0.5)'

					if(alt == false) {
					//	document.getElementById('minibubbleNumber' + key).style.backgroundColor = 'rgba(221,142,238, 0.5)'

						for(i in arrayBubble) {
							if(arrayBubble[i].bubble.getGroupNumber() == groupID && arrayBubble[i].bubble.bubbleID() != bubbleID) {
								for(k in arrayBubble) {
									if(arrayBubble[i].bubble.getGroupNumber() == groupID && arrayBubble[i].bubble.bubbleID() != bubbleID)
										arrayBubble[i].bubble.setGroupID(arrayBubble[i].bubble.bubbleID())
								}
								break;
							}
						}
						groupID = bubbleID;

					}
				}
			}
		});

		//this sets the dblclick event
		$(bubble).bind({
			"dblclick" : function(num) {
				return function() {
					workingBubble = bubbleID
					if(isOpen) {
						if(signature == "inner Function")
							removeBubbleForEver()
						else
							closeBubble(bubbleID)
					} else {
						openBubble(bubbleID)
					}

				}(bubbleID)
			}
		});
		$(bubble).mousedown(function(e) {
			//unselectBubble()
			draggedBubble = container
			startRedoTimer()
			beingDragged = true;
			var last = workingBubble
			console.log(workingBubble)
			if(workingBubble != bubbleID) {
				var x = "#functionNumber" + last
				$(x).css("-webkit-box-shadow", "none")
			} else {
				$("#functionNumber0").css("-webkit-box-shadow", "none")
			}
			workingBubble = bubbleID
			$(bubble).css("-webkit-box-shadow", "0 0 10px #FFF")
			$(bubble).css("zIndex", "3")
			$(container).css("zIndex", "2")
			$(bubble).css("cursor", "move")
		});

		$(bubble).mouseup(function(e) {
			clearInterval(redoTimer);
			draggedBubble = null;
			beingDragged = false;
			$(bubble).css("zIndex", "1")
			$(container).css("zIndex", "0")
			$(bubble).css("cursor", "pointer")

			if(parentBubble != null && !isOpen) {
				parentObjTop = parseInt(document.getElementById("container" + parentBubble).style.top.split("px")[0]);
				parentObjLeft = parseInt(document.getElementById("container" + parentBubble).style.left.split("px")[0]);
				parentObjBottom = parentObjTop + parseInt(document.getElementById("container" + parentBubble).style.height.split("px")[0]);
				parentObjRight = parentObjLeft + parseInt(document.getElementById("container" + parentBubble).style.width.split("px")[0]);
				bubbleTop = parseInt($(container).css("top").split("px")[0]);
				bubbleLeft = parseInt($(container).css("left").split("px")[0])
				bubbleBottom = bubbleTop + parseInt($(container).css("height").split("px")[0]);
				bubbleRight = bubbleLeft + parseInt($(container).css("width").split("px")[0]);

				if((parentObjTop < bubbleTop && bubbleTop < parentObjBottom) && (parentObjLeft < bubbleLeft && bubbleLeft < parentObjRight) || (parentObjTop < bubbleBottom && bubbleBottom < parentObjBottom) && (parentObjLeft < bubbleRight && bubbleRight < parentObjRight) || (parentObjTop < bubbleTop && bubbleTop < parentObjBottom) && (parentObjRight < bubbleRight && bubbleRight < parentObjRight) || (parentObjTop < bubbleBottom && bubbleBottom < parentObjBottom) && (parentObjLeft < bubbleLeft && bubbleLeft < parentObjRight)) {
					$(container).animate({
						opacity : "0"
					}, 400, function() {removeBubbleForEver()
					})
				}

			}
		});
		return bubble;
	}

	//this creates the textArea to edit the bubble code

	return {
		body : returnBody,
		parent : returnParent,
		signature : returnSignature,
		isEditable : returnEditable,
		setEditable : setEditable,
		create : createBubble,
		bubbleID : returnBubbleID,
		isOpen : function(){return isOpen},
		openBubble : openBubble,
		getArea : function() {
			return editableArea;
		},
		getArrayChildren : function() {
			return openChildArray;
		},
		closeBubble : closeBubble,
		getGroupNumber : function() {
			return groupID
		},
		setGroupID : function(newGroupID) {
			groupID = newGroupID
		},
		getGroup : function() {
			return originalGroupElements
		},
		getContainer : function() {
			return container
		}
	}

}

//bubble add

function createInnerFunctionBubble(id) {
	if(!document.getElementById("functionNumber" + id)) {
		arrayBubble[parseInt(id)].bubble.create(id)
		arrayBubble[parseInt(id)].bubble.openBubble(id);
	}
	return arrayBubble[parseInt(id)].bubble;
}

function addNewFunction(index, file) {

	if(!document.getElementById("functionNumber" + index - 1) && functionArray[index-1][0] != null) {
		var b_data = new Bubble("dom", functionArray[index-1][0], getCompleteCode(index - 1));
		arrayBubble[index - 1] = {
			bubble : b_data,
			bubblePath : pathName
		};
		b_data.create(index - 1)

	} else if(functionArray[index-1][0] == null) {
		var b_data = new Bubble("dom", "inner Function", getCompleteCode(index - 1));
		arrayBubble[index - 1] = {
			bubble : b_data,
			bubblePath : pathName
		};
		b_data(index - 1)
	}

}

function add_bubble(pathName) {
	if(myPathName.indexOf(pathName) == -1) {
		myPathName.push(pathName)
		pathIndex.push(lastIndex)
		if(!document.getElementById("functionNumber" + lastIndex)) {
			var b_data = new Bubble("dom", functionArray[lastIndex][0], functionArray[lastIndex][2])
			arrayBubble[lastIndex] = {
				bubble : b_data,
				bubblePath : pathName
			}
			b_data.create(lastIndex)
		}

		for( i = lastIndex + 1; i < functionArray.length; i++) {

			if(!document.getElementById("functionNumber" + i) && functionArray[i][0] != null) {
				var b_data = new Bubble("dom", functionArray[i][0], getCompleteCode(i));
				arrayBubble[i] = {
					bubble : b_data,
					bubblePath : pathName
				};
				//b_data.create(i)

			} else if(functionArray[i][0] == null) {
				var b_data = new Bubble("dom", "inner Function", getCompleteCode(i));
				arrayBubble[i] = {
					bubble : b_data,
					bubblePath : pathName
				};

			}
		}
		lastIndex = functionArray.length
	}

}

function clickForInner(id) {
	if(!document.getElementById("container" + id))
		arrayBubble[workingBubble].bubble.getArrayChildren().push(createInnerFunctionBubble(id));
	workingBubble = id

}

function clickForDefined(id) {
	if(!document.getElementById("container" + id))
		arrayBubble[workingBubble].bubble.getArrayChildren().push(arrayBubble[id].bubble.create(id));
	workingBubble = id

}

function setHeight() {
	document.getElementById("contain").style.height = (window.innerHeight - 50) + "px";
};

//
//
// $(bubble).contextMenu({
// menu: 'menu'
// },
// function(action, el, pos) {
//
// switch(action)
// {
// case "edit/close":
// $(bubble).trigger('dblclick')
// break;
//
// case "cut":
// $(bubble).animate({
// opacity:0.4
// }, 1000);
// break;
//
//
// case "delete":
// removeBubbleForEver();
// break;
//
// case "quit":
// alert(document.getElementsByClassName("edit")[0].innerHTML)
// break;
//
//
// default:
// alert(action)
// }
//
//
//
//
//
// // alert(
// // 'Action: ' + action + '\n\n' +
// // 'Element ID: ' + $(el).attr('id') + '\n\n' +
// // 'X: ' + pos.x + '  Y: ' + pos.y + ' (relative to element)\n\n' +
// // 'X: ' + pos.docX + '  Y: ' + pos.docY+ ' (relative to document)'
// // );
// })